/****************************************
	The Weapons Class that is used to 
	Define how the ubar weapons are used
	in the engine

	By Julian Williams
	Jan 21, 2010
*****************************************/

#include <SFML/Graphics.hpp>
#include <SFML/Audio.hpp>


//old ini file parser, 
//I use iniparser.h now!
//moar portable
//#include <SDL_config_lib.h>

#include <iostream>
#include <fstream>
#include <vector>
#include <sstream>
#include <math.h>


#include "weapons.h"
#include "app.h"
#include "ammo.h"
#include "iniparser.h"
#include "image_manager.h"
#include "player.h"
#include "helper.h"


using namespace std;


//Great Array's for the List and Guns
vector< string > Weapons::List;
vector< Weapons > guns;



int Weapons::max_weapons = 0;


sf::Image default_cursor;





Weapons::Weapons()
{
	state = WS_READY;
}

//Load all of the Weapons from a configuration file
//Called once at the beginning of the program
bool Weapons::Load(std::string cfg_location)
{
	//open file so we can read in all of the weapons and 
	//there properties!
	/*
	CFG_File config;
	int result = CFG_OpenFile(cfg_location.c_str(), &config );

	if ( CFG_OK != result )
	{
 		return false;
    }
    
	//Grab how many weapons there are
	//and resize the guns vector to store them
	max_weapons = CFG_ReadInt("weapon_number", 2);
	*/

	//Grab the Weapon names
	if(!Get_WeaponList()) 
	{ 
		cout << "Get_WeaponList() has FAILED! \nYou should look into this, Julian..." << endl; 
		return false; 
	}

	guns.reserve ( max_weapons );

	//max_weapons = 2;
	cout << "****************************************************************\n";
	cout << "# of Weapons: " << Weapons::max_weapons << endl;


	string wepName;

	//Load default cursor
	default_cursor = Weapons::Load_Cursor("resources/weapons/cursor.png");

	//Loop through and load each weapon 
	for(int i = 0; i < max_weapons; i++)
	{
		//Next 3 lines coverts a string
		//into a number!
		/*
		stringstream StrStream;
		StrStream << i;
		string getName = StrStream.str();

		//grab name of weapon and
		//add to the list
		//wepName = CFG_ReadText(getName.c_str(), "Awesome!");
		//Weapons::list.push_back(wepName);
*/
		cout << "Weapon Name: " << List[i] << "\n\n";


			//add the weapon to the vector
		Weapons weapon;
		guns.push_back(weapon);

			if(!guns[i].Get_Config(List[i])) 
			{
				cout << "Gun: " << List[i] << " failed to load.\n";
				return false;
			}
	}//end for loop


	//if( CFG_OK == CFG_SelectGroup("Game", CFG_False) )
	//CFG_CloseFile(0);
	cout << "****************************************************************\n\n";
	return true;
}//Eof




/* Get/Set is Ready option */
bool Weapons::Get_isReady() { return isReady; }
void Weapons::Set_isReady(bool wpnReady) { isReady = wpnReady; }




/* Grab the Weapons List */
bool Weapons::Get_WeaponList()
{

	//Get texture directory
	string wList_loc("resources/weapons/weapon_list.cfg");
	string weapon_name;


	//Open up Texture List file
	ifstream wList_file(wList_loc.c_str());
    
	//if file isn't open, return false
	if(!wList_file.is_open()) { return false; }

	do 
	{
		//Read in every line
		getline( wList_file, weapon_name);

		if(weapon_name == "") { break; }

		List.push_back(weapon_name);

	} while( !wList_file.eof() );

	//save the number of textures 
	max_weapons = List.size();

	//Close file
	wList_file.close();

	return true;
}//end ov function




//Load the Properties of a weapon
bool Weapons::Get_Config(std::string folder_name)
{
	
//grab and create the nessisary directories
	string folder_location = string("resources/weapons/") + folder_name + string("/");
	string image_location = folder_location + string("image.png");
	string muzzleFl_location = folder_location + string("muzzle_flash.png");

	string cfg_location = folder_location + string("properties.cfg");
	string snd_location = folder_location + string("fire.wav");


	cout << "Loading Gun folder: " << folder_location << endl;
	cout << "Gun Config from: " << cfg_location << endl;
	cout << "Gun sound from: " << snd_location << endl;
	cout << "Gun Image from: " << image_location << "\n\n";


	//Grab the image and apply a color mask
	if(!Load_Image(image_location)) { return false; }

	//Load muzzle Flash
	muzzleFlash_img = gImageManager.getResource( muzzleFl_location );
    if( muzzleFlash_img != NULL ) 
	{
        muzzle_flash.SetImage( *muzzleFlash_img );
    }
//Now Grab the firing sound for the gun
	if(!Load_Sounds(s_fire, SND_fire, snd_location)) { return false; }



//Grab weapon config



		dictionary	*	ini = iniparser_load(cfg_location.c_str());

		if (ini==NULL)
		{
			cout << "Couldn't load configuration file, sorry :P \n";
			return false;
		}

//Get all of the properties
	
		name = iniparser_getstring(ini, "gun:name", "Default");
		ammo_per_shot = iniparser_getint(ini, "gun:ammo_per_shot", 1);
		max_ammo = iniparser_getint(ini, "gun:max_ammo", 0);

		spread_angle = iniparser_getint(ini, "gun:spread_angle", 5);

		bullet_name = iniparser_getstring(ini, "gun:bullet_name", ".34 Calibur");

		use_custom_cursor = iniparser_getboolean(ini, "gun:use_custom_cursor", 0);

		cout << "Name: " << name << endl;
		cout << "Ammo Per Shot: " << ammo_per_shot << endl;
		cout << "Max Ammo: " << max_ammo << endl;
		cout << "Custom Cursor: " << use_custom_cursor << endl;


	//Animation related information
	
		tile_size.x = iniparser_getint(ini, "animation:tile_width", 100);
		tile_size.y = iniparser_getint(ini, "animation:tile_height", 50);

		cout << "Tile Size.X: " << tile_size.x << endl;
		cout << "Tile Size.Y: " << tile_size.y << endl;

		pivit_point.x = iniparser_getint(ini, "animation:pivit_point_x", 18);
		pivit_point.y = iniparser_getint(ini, "animation:pivit_point_y", 20);

		cout << "Pivit Point.X: " << pivit_point.x << endl;
		cout << "Pivit Point.Y: " << pivit_point.y << endl;


		end_point.x = iniparser_getint(ini, "animation:end_point_x", 18);
		end_point.y = iniparser_getint(ini, "animation:end_point_y", 20);

		cout << "End Point.X: " << end_point.x << endl;
		cout << "End Point.Y: " << end_point.y << endl;

		muzzle_point.x = iniparser_getint(ini, "animation:muzzle_point_x", muzzle_flash.GetImage()->GetWidth());
		muzzle_point.y = iniparser_getint(ini, "animation:muzzle_point_y", muzzle_flash.GetImage()->GetHeight());

		cout << "Muzzle Point.X: " << muzzle_point.x << endl;
		cout << "Muzzle Point.Y: " << muzzle_point.y << endl;


		shootFrame.start = iniparser_getint(ini, "animation:shoot_start", 3);
		shootFrame.end   = iniparser_getint(ini, "animation:shoot_end", 4);
		shootFrame.speed = iniparser_getdouble(ini, "animation:shoot_frame_speed", 50);

		fire_delay = iniparser_getdouble(ini, "animation:fire_delay", 1);

		cout << "ShootFrame Start: " << shootFrame.start << ", ShootFrame End: " << shootFrame.end << ", shootFrame Speed: " << shootFrame.speed << "\n\n";
		cout << "**********************************************************\n\n";
	


	//Load the nessissary weapon cursor
	if(!use_custom_cursor) 
	{
		//just use defualt if one not specified
		cursor.SetImage(default_cursor);
	}else{
		//use custom cursor
		cursor.SetImage(Weapons::Load_Cursor(folder_location + string("cursor.png")));
	}

	cursor.SetOrigin(cursor.GetImage()->GetWidth() * 0.5, cursor.GetImage()->GetHeight() * 0.5);

	//end_point.x = CFG_ReadFloat("end_point_x", 91);
//	end_point.y = CFG_ReadFloat("end_point_y", 15);

//Set Pivit point from which the gun will rotate round
	Set_PivitPoint(pivit_point);
	//Set_EndPoint(end_point);

//close cfg file
	//CFG_CloseFile(0);

	return true;
}//EoF




/* Load Main sound filea of the weapon */
bool Weapons::Load_Sounds(sf::Sound& s, sf::SoundBuffer& b, std::string snd_location)
{
	//Load Image
	if(!b.LoadFromFile(snd_location)) 
	{ 
		return false; 
	}

	s.SetBuffer(b);
	
	return true;
}//EoF



/* Setup the cursor sprite to use the specified cursor image */
sf::Image Weapons::Load_Cursor(string cursorLocation)
{

	sf::Image img;

	cout << "Loading Cursor from: " << cursorLocation << "\n\n";

	if(!img.LoadFromFile(cursorLocation)) 
	{ 
		cout << "Cursor Image: " << cursorLocation << " Failed to Load!\n";
	}

	img.CreateMaskFromColor(sf::Color(255, 0, 255), 0);
	//cursor.SetImage(img);

	//cursor.SetCenter(img.GetWidth()/2, img.GetHeight()/2);

	return img;
}//EoF



/* Set the Pivit Point for the Gun to rotate and follow around */
void Weapons::Set_PivitPoint(sf::Vector2f pp)
{
	SetOrigin(pp);
}

/* Set/Get the End point, from which to use rotate values from */
void Weapons::Set_EndPoint(sf::Vector2f ep)
{
	current_ep = ep;
}





/* Load Weapon Image - Moved to Objects class
bool Weapons::Load_Image(std::string img_location)
{

	//Load Image
	if(!Image.LoadFromFile(img_location)) { return false; }
	//Make magic pink invisable!
	Image.CreateMaskFromColor(sf::Color(255, 0, 255), 0);

	SetImage(Image);

	return true;
}//EoF

*/




/* Update animation Timestep*/
void Weapons::Animation_Update()
{
	static float i = 0;
	
	if(Get_State() == WS_FIRING)
	{

		counter += shootFrame.speed * App::getInstance().Get_RenderWindow()->GetFrameTime(); //animate running according to speed
                   
		
	
                   if(counter >= 1.5) 
				   {
                             counter = 0;

                                    if(frame < shootFrame.end) { frame++; }
                                    else 
									{ 
										frame = 0;
										Set_State(WS_DELAY); 
									}  
                   }//counter check
    
	}else if( Get_State() == WS_RELOADING)
	{
		  //implement later

    }else if( Get_State() == WS_DELAY)
	{
		

		if(i < 1.5) { i += fire_delay * App::getInstance().Get_RenderWindow()->GetFrameTime(); }
		else { i = 0; Set_State(WS_READY); }

		//cout << "Fire_delay = " << fire_delay << ", I = " << i << endl;
	}else if( Get_State() == WS_READY)
	{
		  frame = 0; 
		  counter = shootFrame.speed;
	}

	//Engage Animatron!
	 Tile_Update();
}//EoF





/* Update the on screen weapons mechanics */
void Weapons::Mechanics_Update()
{

	
	//static sf::Vector2f inverse, inverse_shoulder;
	//convert to view coords
	//sf::Vector2f MousePos = App::getInstance().Get_RenderWindow()->ConvertCoords(App::getInstance().Get_RenderWindow()->GetInput().GetMouseX(), App::getInstance().Get_RenderWindow()->GetInput().GetMouseY());

	//update cursor position
	cursor.SetPosition(App::getInstance().Get_MousePosition());

	//Rotate to track mouse cords!
	Set_Angle(((-1* 360 / 3.1415926535 * (atan2(   static_cast<double> (GetPosition().y -App::getInstance().Get_MousePosition().y) , static_cast<double> (GetPosition().x - App::getInstance().Get_MousePosition().x))))/2)+180);
		//-1* 360 / 3.1415926535 * (atan2(   static_cast<float> (end_point.y - App.GetInput().GetMouseY()) , static_cast<float> (end_point.x - App.GetInput().GetMouseX())));

	//regulate angles
	//if(angle > 359) { angle = 0; }
	//else if(angle < 0) { angle = 359; }


	

		Set_PivitPoint(pivit_point);
		Set_EndPoint(end_point);

		//Handle sound Spacialization
		s_fire.SetPosition(sf::Listener::GetPosition().x, sf::Listener::GetPosition().y, 0);




		//Set up muzzle flash
			muzzle_flash.SetOrigin(muzzle_point);
			muzzle_flash.SetPosition(Get_MuzzlePoint(Get_VelocityDirection()));
			muzzle_flash.SetRotation(Get_Angle());

		Animation_Update();

		
	//move to follow player
		SetPosition (player.GetPosition() + player.Get_ShoulderPoint());
	   // SetRotation (Get_Angle());
		
}//EoF




/* Get Velocity Direction */
sf::Vector2f Weapons::Get_VelocityDirection()
{
	//Very important direction code!!!!!!!!!
			sf::Vector2f temp_direction;
			temp_direction.x = cos(-1 * degreesToRadians(Get_Angle()));
			temp_direction.y = sin(degreesToRadians(Get_Angle()));
	return temp_direction;
}//EoF



/* Spawn bullet and Set its velocity */
void Weapons::Spawn_Bullet(Particles &ammo_type)
{



			ammo_type.Set_State(AS_ACTIVE);

			//b.SetOrigin(10, ammo_type.tile_size.y/2);

			//b.Set_Angle(ammo_type.Get_Angle());

		//	b.Set_Damage(ammo_type.Get_Damage());

			//bullets[i].Set_SpreadAngle(ammo_type.Get_SpreadAngle());
			ammo_type.speed = sf::Randomizer::Random(ammo_type.min_speed, ammo_type.max_speed);

	
		
			//bullets[i].Set_SpreadAngle(ammo_type.Get_SpreadAngle());
			//b.Set_Speed(ammo_type.Get_Speed() * sf::Randomizer::Random(0.02f, 1.2f));

			int random_dir = sf::Randomizer::Random(-Get_SpreadAngle(), Get_SpreadAngle());

		//Very important direction code!!!!!!!!!
			sf::Vector2f temp_direction;
			temp_direction.x = cos(-1 * degreesToRadians(Get_Angle() + random_dir));
			temp_direction.y = sin(degreesToRadians(Get_Angle() + random_dir));


//Set the Velocity of the bullet
			
			ammo_type.velocity.x =  ammo_type.Get_Speed() * temp_direction.x;
			ammo_type.velocity.y = -ammo_type.Get_Speed() * temp_direction.y;
                                       
	

			//Set Image info
		//	ammo_type.SetImage(*ammo_type.img);
			

			ammo_type.SetRotation(Get_Angle()+random_dir);


			Bullets.Emit(ammo_type, Get_MuzzlePoint(Get_VelocityDirection()), 1);

	//Add new bullet to the list'
	//bullet_list.push_back(b);
		

}//EoF




/* Get Muzzle Point */
sf::Vector2f Weapons::Get_MuzzlePoint(sf::Vector2f temp_direction)
{
	
		sf::Vector2f new_mp;

		new_mp.x = GetPosition().x + (Get_EndPoint().x * temp_direction.x);
		new_mp.y = (GetPosition().y + Get_EndPoint().y) + (-Get_EndPoint().x * temp_direction.y);

		return new_mp;
}//EoF


